home *** CD-ROM | disk | FTP | other *** search
Wrap
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" > <head> <title>Feed preview</title> <style type="text/css"> html, body { margin:0; padding:0; border:0; } body { color:#000; background:#fff; text-align:center; font:normal normal .9em/1.5em sans-serif; padding:2em 0; } body[class]:after { position:fixed; top:0; left:0; right:0; bottom:0; background:#fff; content:attr(class); text-transform:uppercase; padding-top:30%; text-align:center; } h1 { margin:0; font-size:1.5em; line-height:1.5em; display:inline; } h1:before { display:inline; overflow:hidden; vertical-align:middle; content:-o-skin('Mail Newsfeeds'); margin-right:.2em; line-height:1.5em; } #heading { background:#a00 url(data:image/png,%89PNG%0D%0A%1A%0A%00%00%00%0DIHDR%00%00%00%04%00%00%00%C0%08%06%00%00%00%23%88%C2%DC%00%00%00%04gAMA%00%00%AF%C87%05%8A%E9%00%00%00%19tEXtSoftware%00Adobe%20ImageReadyq%C9e%3C%00%00%00%3AIDATx%DA%EC%D0%21%0E%000%08%04Ah%8A%EF%FF%3F%7BE%12%0C%02%BB%9B%9C%19y.%C9j%C7Z%00%00%00%000%82%E7%A2%C2%CD%BD%0E%C1c%00%00%00%C0%0E%BE%00%03%00k%9B%04%9A%B9%BDH%AF%00%00%00%00IEND%AEB%60%82) repeat-x center center; color:#fff; padding:8px; margin:1em 0; border:2px solid #eee; border-width:2px 0; } #heading > * { display:inline-block; width:50ex; line-height:2em; } #heading a { color:#fff; } #heading button { margin:0 10ex; width:30ex; } a { text-decoration:none; } a:hover { text-decoration:underline; } #items { display:block; clear:both; text-align:center; margin:2em 0; padding:0; overflow:hidden; } #items > ul { position:relative; list-style:none; margin:0; padding:0; border:0; width:auto; display:inline-block; text-align:left; } #items > ul > li:last-child { display:none; } #items > ul > li { vertical-align:top; font:normal normal .8em/1.6em sans-serif; display:inline-block; margin:2em; padding:0; width:50ex; } #items > ul > li > h2 { font:normal lighter 1.66em/1.2em sans-serif; margin:0; color:#000; overflow:hidden; -o-text-overflow:ellipsis; } #items > ul > li > h2 > a { display:block; color:inherit; padding:0; } #items > ul > li a { color:#b00; } #items > ul > li > div { border-top:1px solid #ccc; text-align:justify; margin:1em 0 0 0; padding:1em 0 3em 0; color:#555; vertical-align:top; -o-text-overflow:ellipsis; } #items > ul > li > div pre { font:.9em/.9em monospace; background:#eee; overflow:auto; border:1px solid #999; border-width:1px 0; padding:1em; } #items > ul > li > div pre a { font-style:normal; } #items > ul > li > div p { margin:0 0 2em 0; } #items > ul > li > div a { font-style:italic; margin-right:.25em; } #items > ul > li > div img { display:none; } #items > ul > li > div img[src] { float:left; display:inline-block; border:1px solid #aaa; padding:1px; margin:1px; margin:1px 8px 8px 1px; max-width:100%; } #items > ul > li > div a img[src] { border-color:#a00; } #items > ul > li > div a:hover img { border-width:2px; margin:0px 7px 7px 0px; } #footer { font-size:.85em; } #footer a { color:#b00; } /* * extra rules for HANDHELD devices */ @media handheld { body { font:normal normal 1em/1.5em sans-serif; padding:1em 0; } #heading > *, #heading > button { display:inline; width:auto; margin:0 .5em; line-height:auto; height:auto; } #items { margin:1em 0; } #items > ul { display:block; } #items > ul > li { font:normal normal 1em/1.5em sans-serif; display:block; padding:1em; margin:0; width:auto; background:#fff; } #items > ul > li:nth-child(2n) { background:#eee; } #items > ul > li > h2 { font:normal bold 1.33em/1.2em sans-serif; } #items > ul > li > div { border:0; padding:0; margin:0; } #items > ul > li > div:after { clear:both; content:' '; display:block; } #items > ul > li > div pre { font:1em/1em monospace; background:#ddd; } #items > ul > li > div a { font-style:normal; } #footer a { font-size:1em; } } </style> <script type="text/javascript"> // <![CDATA[ String.prototype.trim = function() { return this.replace( /^\s+|\s+$/g, '' ); } /* * whiteList * tags + attributes and method to validate them */ HTMLElement.prototype.whiteList = { 'A': { '__precondition__':function( node ) { return node.hasAttribute('href') && node.whiteList['A'].href.call( {value:node.getAttribute('href')}, node ); }, 'href':function( node ) { return null!=this.value.match( /^https?:\/\//i ); }, 'title':true } ,'IMG': { '__precondition__':function( node ) { node.setAttribute( 'title', node.getAttribute('title')||node.getAttribute('src') ) return node.hasAttribute('src') && node.whiteList['IMG'].src.call( {value:node.getAttribute('src')}, node ); }, 'src':function( node ) { return null!=this.value.match( /^https?:\/\//i ); }, 'alt':true, 'title':true } ,'P':{} ,'PRE':{} ,'UL':{} ,'OL':{} ,'LI':{} ,'DL':{} ,'DT':{} ,'H1':{} ,'H2':{} ,'H3':{} ,'H4':{} ,'H5':{} ,'H6':{} ,'BR':{} } /** * Prototype extension to simplify adding and sanitizing markup to an element. * arguments = some strings containing the HTML markup to sanitize and append */ HTMLElement.prototype.appendMarkup = function( content, maxLength ) { var maxLength = maxLength||Infinity, dummy = document.createElement('div'); dummy.innerHTML = content; // sanitize using the whiteList dummy.sanitize(); // append DOM tree of dummy in this var i = 0, node; while( maxLength>this.textContent.length && dummy.firstChild ) { this.appendChild( dummy.firstChild ); i++; } //maxLength = Infinity; if( dummy.firstChild && maxLength!=Infinity ) { this.cutOff( maxLength ); } return this; } /** * Prototype extension to sanitize the attributes and HTMLElements * whiteList = { 'NODENAME_0':{'attribute_0':function(){},'attribute_1':function(){}} } */ HTMLElement.prototype.sanitize = function() { // recurse var i=0, previousNodeName='/', currentNode; while( currentNode=this.childNodes[i] ) { var nodeName = currentNode.nodeName; if ( currentNode.nodeType==1 && ( !this.whiteList[nodeName] || ( this.whiteList[nodeName] && this.whiteList[nodeName].__precondition__ && !this.whiteList[nodeName].__precondition__(currentNode) ) || ( nodeName=='BR' && ( previousNodeName=='BR' || previousNodeName=='P' ) ) ) ) { // either it's not in the whiteList or does not meet the preconditions or is an extra BR -> replace currentNode by its content while( currentNode.firstChild ) { this.insertBefore( currentNode.firstChild.cloneNode( true ), currentNode ); currentNode.removeChild( currentNode.firstChild ); } this.removeChild( currentNode ); } else { if( currentNode.nodeType==1 ) { // in the whiteList and meet the preconditions // -> sanitize the attributes for( var j=currentNode.attributes.length,attribute; attribute=currentNode.attributes[--j]; ) { var attrSanity = this.whiteList[nodeName][attribute.name]; if( attrSanity===undefined || ( attrSanity!==true && false==attrSanity.apply(attribute,[currentNode] ) ) ) { currentNode.removeAttribute( attribute.name ); } } // -> and recurse currentNode.sanitize(); previousNodeName = nodeName; } // => next! i++; } } } /* * Prototype extension to cutOff a DOM tree so as to get a textContent <= maxLength */ Element.prototype.cutOff = function( maxLength, base ) { var base = base||this; while( this.lastChild ) { if( this.lastChild.nodeType==3 && this.lastChild.nodeValue.length>base.textContent.length-maxLength ) { this.lastChild.nodeValue = this.lastChild.nodeValue.slice( 0, this.lastChild.nodeValue.length-base.textContent.length+maxLength ) +'...'; return true; } if( this.lastChild.nodeType==1 && this.lastChild.cutOff( maxLength, base ) ) { return true; } this.removeChild( this.lastChild ); } return false; } // failsafe for opera.locale.getLocaleString opera.locale=opera.locale||{'getLocaleString':function(){return ''}}; /* * outputFeed */ function outputFeed( feed, status ) { if( !feed ) { var statusName = ['NO FEED ITEMS','CANCELED','REFRESH POSTPONED','NOT MODIFIED','OUT OF MEMORY','SERVER TIMEOUT','LOADING ERROR','PARSING ERROR'] document.body.className = 'error #'+ status +' ( '+ statusName[ status ] +' )'; return false; } // l10n the 'footer' note including a link var footer = document.getElementById('footer'), splitText = (opera.locale.getLocaleString( 'S_WEBFEEDS_FOOTER' )||'This page was generated by Opera from %s').split('%s'); footer.firstChild.nodeValue = splitText.shift()||''; footer.lastChild.nodeValue = splitText.join(' ')||''; // l10n the 'learn' link (document.getElementById('learn')||{firstChild:{}}).firstChild.nodeValue = opera.locale.getLocaleString( 'S_WEBFEEDS_SUBSCRIBE_HINT' )||'Learn more about feeds'; // subscribeNative? var button = document.getElementById('subscribe'); if( button ) { if( 'function'==typeof(opera.feeds.subscribeNative) ) { button.addEventListener( 'click', function(){ opera.feeds.subscribeNative(location.href); }, false ); // l10n the 'subscribe' button button.firstChild.nodeValue = opera.locale.getLocaleString( 'S_MINI_FEED_SUBSCRIBE' )||'Subscribe'; } else { button.parentNode.removeChild( button ); } } // set title top.document.title = document.getElementById('feedTitle').firstChild.nodeValue = document.createElement( 'div' ).appendMarkup( feed.title.data ).textContent.trim()||feed.uri; document.body.removeAttribute( 'class' ); // walk the feed items var cutOff = 768, hItemsUl = document.getElementById('itemsUl'), noTilteStr = opera.locale.getLocaleString( 'M_BREW_NO_TITLE' )||'<No Title>'; for( var i=0,feedEntry; feedEntry=feed.entries[i++]; ) { var itemLi = hItemsUl.lastChild.cloneNode( true ); // set the href itemLi.firstChild.firstChild.setAttribute( 'href', feedEntry.uri||'#' ); // set the title itemLi.firstChild.firstChild.firstChild.nodeValue = document.createElement( 'div' ).appendMarkup( feedEntry.title.data ).textContent.trim()||noTilteStr; // write content if( feedEntry.content.isMarkup ) { itemLi.lastChild.appendMarkup( (feedEntry.content.data.trim()||'\xa0'), cutOff ); } else if( feedEntry.content.isPlainText ) { itemLi.lastChild.appendChild( document.createTextNode( (feedEntry.content.data.trim()||'\xa0').slice( 0, cutOff ) ) ); } else { itemLi.lastChild.appendChild( document.createTextNode( (feedEntry.content.data||'\xa0').slice( 0, cutOff ) ) ); } // append itemLi to hItemsUl hItemsUl.insertBefore( itemLi, hItemsUl.lastChild ); } return true; } // ]]> </script> </head> <body class='loading'> <h1 id="feedTitle">Title of the news feed</h1> <div id="heading"><span><a id="learn" href="opera:/help/feeds.html">Learn more about feeds</a></span><button id="subscribe">Subscribe</button></div> <div id="items"> <ul id="itemsUl"><!-- template LI follows --><li><h2><a href="#">...</a></h2><div></div></li></ul> </div> <div id="footer">This page was generated by Opera from <a href="#">here</a>.</div> <script type="text/javascript"> // <![CDATA[ window.addEventListener ( 'load', function(/* window.load */) { var url = location.href.split('#')[0], here = document.getElementById('footer').getElementsByTagName('A')[0], theFeed = null; for( var i=0; theFeed=opera.feeds.allFeeds[i++]; ) { if( url==theFeed.uri.split('#')[0] ) { here.firstChild.nodeValue = here.href = theFeed.uri; break; } } outputFeed( theFeed ); }, false ); //]]> </script> </body> </html>